﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace Red.Controls.Indicators
{
    public class BindToSelf : Binding
    {
        public BindToSelf()
            : base()
        {
            Configure();
        }

        public BindToSelf( string path )
            : base( path )
        {
            Configure();
        }

        private void Configure()
        {
            RelativeSource = new RelativeSource( RelativeSourceMode.FindAncestor, typeof( UserControl ), 1 );
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        }
    }
 
    public partial class Circle : UserControl
    {
        #region Private Properties

        /// <summary>
        /// Point from which the arc starts drawing
        /// </summary>
        private Point Start
        {
            get { return (Point)GetValue( StartProperty ); }
            set { SetValue( StartProperty, value ); }
        }

        private static readonly DependencyProperty StartProperty =
        DependencyProperty.Register
        (
            "Start",
            typeof( Point ),
            typeof( Circle ),
            new PropertyMetadata( new Point( 0, 0 ), null )
        );

        /// <summary>
        /// End of the arc
        /// </summary>
        private Point End
        {
            get { return (Point)GetValue( EndProperty ); }
            set { SetValue( EndProperty, value ); }
        }

        private static readonly DependencyProperty EndProperty =
        DependencyProperty.Register
        (
            "End",
            typeof( Point ),
            typeof( Circle ),
            new PropertyMetadata( new Point( 0, 0 ), null )
        );

        /// <summary>
        /// End of the arc
        /// </summary>
        private bool IsLargeArc
        {
            get { return (bool)GetValue( IsLargeArcProperty ); }
            set { SetValue( IsLargeArcProperty, value ); }
        }

        private static readonly DependencyProperty IsLargeArcProperty =
        DependencyProperty.Register
        (
            "IsLargeArc",
            typeof( bool ),
            typeof( Circle )
        );

        /// <summary>
        /// Width and Height of the circle (or ellipsis)
        /// </summary>
        private Size Size
        {
            get { return (Size)GetValue( SizeProperty ); }
            set { SetValue( SizeProperty, value ); }
        }

        private static readonly DependencyProperty SizeProperty =
        DependencyProperty.Register
        (
            "Size",
            typeof( Size ),
            typeof( Circle ),
            new PropertyMetadata ( new Size( 0, 0 ), null )
        );

        /// <summary>
        /// Text in the centre of the control that displays the progress
        /// </summary>
        private string Text
        {
            get { return (string)GetValue( TextProperty ); }
            set { SetValue( TextProperty, value ); }
        }

        private static readonly DependencyProperty TextProperty =
        DependencyProperty.Register
        (
            "Text",
            typeof( string ),
            typeof( Circle ),
            new PropertyMetadata( @"0%", null )
        );

        #endregion Private Properties

        #region Public Properties

        /// <summary>
        /// Determines the visibility of the text at the centre of the circle
        /// </summary>
        public bool ShowText
        {
            get { return (bool)GetValue( ShowTextProperty ); }
            set { SetValue( ShowTextProperty, value ); }
        }

        public static readonly DependencyProperty ShowTextProperty =
        DependencyProperty.Register
        (
            "ShowText",
            typeof( bool ),
            typeof( Circle ),
            new PropertyMetadata( true )
        );

        /// <summary>
        /// Specifies the size of the circle relative to the size of the control
        /// 0.0 -> 1.0
        /// </summary>
        public double Radius
        {
            get { return (double)GetValue( RadiusProperty ); }
            set { SetValue( RadiusProperty, value ); }
        }

        public static readonly DependencyProperty RadiusProperty =
        DependencyProperty.Register
        (
            "Radius",
            typeof( double ),
            typeof( Circle ),
            new PropertyMetadata
            (
                1.0,
                ( o, e ) =>
                {
                    Circle li = (Circle)o;

                    li.RecalculatePoints();
                }
            )
        );

        /// <summary>
        /// Specifies how complete the circle currently is
        /// 0.0 -> 1.0
        /// </summary>
        public double Progress
        {
            get { return (double)GetValue( ProgressProperty ); }
            set { SetValue( ProgressProperty, value ); }
        }

        public static readonly DependencyProperty ProgressProperty =
        DependencyProperty.Register
        (
            "Progress",
            typeof( double ),
            typeof( Circle ),
            new PropertyMetadata
            (
                0.0,
                ( o, e ) =>
                {
                    Circle li = (Circle)o;
                    li.RecalculatePoints();
                    li.Text = String.Format( @"{0:d}", (int)( ( li.Progress * 100.0 ) + 0.5 ) );
                }
            )
        );

        /// <summary>
        /// Width of the line being drawn
        /// </summary>
        public double Thickness
        {
            get { return (double)GetValue( ThicknessProperty ); }
            set { SetValue( ThicknessProperty, value ); }
        }

        public static readonly DependencyProperty ThicknessProperty =
        DependencyProperty.Register
        (
            "Thickness",
            typeof( double ),
            typeof( Circle ),
            new PropertyMetadata( 5.0, null )
        );

        #endregion Public Properties

        #region C-Tor

        public Circle()
        {
            InitializeComponent();

            SizeChanged += Circle_SizeChanged;
        }

        #endregion C-Tor

        #region Event Handlers

        private void Circle_SizeChanged( object sender, SizeChangedEventArgs e )
        {
            RecalculatePoints();
        }

        #endregion Event Handlers

        #region Protected Methods

        protected void RecalculatePoints()
        {
            double actualWidth = Math.Max( ActualWidth - Thickness, 0 );
            double actualHeight = Math.Max( ActualHeight - Thickness, 0 );

            Size = new Size( Radius * actualWidth * 0.5, Radius * actualHeight * 0.5 );

            Start = new Point
            (
                Size.Width,
                0
            );

            End = new Point
            (
                Size.Width * Math.Cos( Progress * Math.PI * 2 ),
                Size.Height * Math.Sin( Progress * Math.PI * 2 )
            );

            IsLargeArc = Progress > 0.5;
        }

        #endregion Protected Methods
    }
}
